#include "mainWindow.h"
#include "ui_mainwindow.h"
#include "core/DataFormatter.h"
#include "core/DriverManager.h"
#include "control/DataControl.h"
#include "ui/CustomTreeStyle.h"
#include "C0C_Def.h"

#include <QMessageBox>
#include <QInputDialog>
#include <QDateTime>
#include <QScrollBar>
#include <QStyleFactory>
#include <QApplication>
#include <QHeaderView>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_driverController(new DriverController(this))
    , m_dataControl(new DataControl(this))
    , m_refreshTimer(new QTimer(this))
    , m_isRunning(false)
    , m_dataFlushThresholdBytes(512)
{
    // 让 ADD_LOG 在构造期间即可拿到有效的 MWIND
    qApp->setProperty("stApp", QVariant::fromValue(this));

    ui->setupUi(this);

    // Initialize data flush timer for small data
    m_dataFlushTimer = new QTimer(this);
    m_dataFlushIntervalMs = 200;
    m_dataFlushTimer->setInterval(m_dataFlushIntervalMs);
    connect(m_dataFlushTimer, &QTimer::timeout, this, &MainWindow::onDataFlushTimerTick);
    m_dataFlushTimer->start();

    initializeUi();
    initializeConnections();
    initializeDeriver();

    // Set initial default values
    ui->baudRateComboBox->setCurrentText("115200");
    ui->dataBitsComboBox->setCurrentText("8");
    ui->parityComboBox->setCurrentIndex(0); // No parity
    ui->stopBitsComboBox->setCurrentIndex(0); // 1 stop bit
    ui->flowControlComboBox->setCurrentIndex(0); // No flow control

    // Refresh serial port list
    refreshSerialPorts();

    // Set timer for periodic refresh
    m_refreshTimer->setInterval(5000); // Refresh every 5 seconds
    connect(m_refreshTimer, &QTimer::timeout, this, &MainWindow::refreshSerialPorts);
    m_refreshTimer->start();

    // Status bar
    m_statusLabel = new QLabel("Ready");
    statusBar()->addPermanentWidget(m_statusLabel);
    m_statsLabel = new QLabel("Rx 0 B/s | Tx 0 B/s | Out 0 B/s | EP 0 B/s | Err 0");
    statusBar()->addPermanentWidget(m_statsLabel);

    // endpoint List has been extended
    ui->endpointListWidget->setSelectionMode(QListWidget::ExtendedSelection);
    ui->dataLogTextEdit->setReadOnly(true);

    updateUiState();
}

MainWindow::~MainWindow()
{
    if (m_isRunning) {
        m_dataControl->stopService();
    }
    delete ui;
}

void MainWindow::initializeUi()
{
    // Set window title
    setWindowTitle("Serial Port Splitter");

    // Set window size
    // 限定于ui文件中定义
    // resize(800, 600);
}

void MainWindow::initializeConnections()
{
    // Button connections
    connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::refreshSerialPorts);
    connect(ui->startStopButton, &QPushButton::clicked, this, &MainWindow::onStartStopButtonClicked);
    connect(ui->addSerialButton, &QPushButton::clicked, this, &MainWindow::onAddSerialEndpointClicked);
    connect(ui->addUdpButton, &QPushButton::clicked, this, &MainWindow::onAddUdpEndpointClicked);
    connect(ui->removeButton, &QPushButton::clicked, this, &MainWindow::onRemoveEndpointClicked);
    connect(ui->clearLogButton, &QPushButton::clicked, this, [this]{
        ui->dataLogTextEdit->clear();
        m_asciiPendingBySource.clear();
        m_printedHeaders.clear();
        m_lastLogHeader.clear();
    });
    connect(ui->taskLogClearBtn, &QPushButton::clicked, this, [&]{ ui->taskLogEdit->clear(); });
    connect(ui->sendButton, &QPushButton::clicked, this, &MainWindow::onSendButtonClicked);
    // Enter key
    connect(ui->dataInputEdit, &QLineEdit::returnPressed, this, &MainWindow::onSendButtonClicked);
    /// Virtual serial port manager connections
    connect(ui->refreshVirtualPortButton, &QPushButton::clicked, m_driverController, &DriverController::refreshVirtualPortList);
    connect(ui->createVirtualPortButton, &QPushButton::clicked, m_driverController, &DriverController::createPortPairSignal);
    connect(ui->removeVirtualPortButton, &QPushButton::clicked, this, [&] {
        auto idx = ui->virtualPortTreeView->currentIndex();
        if (idx.isValid()) {
            const PortPair* pair = m_driverController->getPortDeviceModel()->getPairInfo(idx);
            emit m_driverController->removedPortPairSignal(pair->pairNum());
        }
    });
    connect(ui->endpointListWidget, &EndPointListWidget::newPortAdded, this, &MainWindow::addSerialPortToEndPoints);

    // Menu connections
    connect(ui->actionExit, &QAction::triggered, this, &QMainWindow::close);
    connect(ui->actionAbout, &QAction::triggered, this, [this]() {
        QMessageBox::about(this, "About", "Serial Port Splitter v1.0\n\nA tool that splits a physical serial port into multiple serial/UDP outputs, supporting full-duplex communication.");
    });

    // Driver Controller connections
    connect(m_driverController->getPortDeviceModel(), &PortDeviceModel::dataChanged, this, &MainWindow::refreshSerialPorts);
    connect(m_dataControl, &DataControl::InputPortDataReceived, this, &MainWindow::onInputPortDataReceived);
    connect(m_dataControl, &DataControl::EndPointPortDataReceived, this, &MainWindow::onEndpointPortDataReceived);
    connect(m_dataControl, &DataControl::error, this, &MainWindow::onError);
    connect(m_dataControl, &DataControl::StatsUpdated, this, &MainWindow::onStatsUpdated);

    // Main Window Connections
    connect(this, &MainWindow::newLogMessage, this, &MainWindow::addLogMessage);
}

void MainWindow::initializeDeriver()
{
    m_driverController->initialize();
    // 设置模型到View
    ui->virtualPortTreeView->setModel(m_driverController->getPortDeviceModel());
    // 启用拖拽
    ui->virtualPortTreeView->setDragEnabled(true);
    ui->virtualPortTreeView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->virtualPortTreeView->setDragDropMode(QAbstractItemView::DragOnly);
    // 二级结构显示：顶层为总线设备，子级为两个固定端口
    ui->virtualPortTreeView->setRootIsDecorated(true);
    ui->virtualPortTreeView->setItemsExpandable(true);
    ui->virtualPortTreeView->setUniformRowHeights(true);
    ui->virtualPortTreeView->setHeaderHidden(true);
    // 配置列宽与伸展
    ui->virtualPortTreeView->setColumnWidth(0, 220);
    ui->virtualPortTreeView->setColumnWidth(1, 90);
    ui->virtualPortTreeView->setColumnWidth(2, 90);
    ui->virtualPortTreeView->setColumnWidth(3, 160);
    ui->virtualPortTreeView->header()->setStretchLastSection(true);
    // 应用自定义分支线与展开图标样式（同时作用于 viewport，避免样式未下发导致的绘制差异）
    ui->virtualPortTreeView->setStyle(new CustomTreeStyle(ui->virtualPortTreeView->style()));
    ui->virtualPortTreeView->viewport()->setStyle(new CustomTreeStyle(ui->virtualPortTreeView->style()));
    ui->virtualPortTreeView->setItemDelegate(new CustomItemDelegate(ui->virtualPortTreeView));

    ui->virtualPortTreeView->expandAll();
}

/***************** Tool Function *****************/

void MainWindow::updateUiState()
{
    bool isRunning = m_isRunning;

    // Update start/stop button
    ui->startStopButton->setText(isRunning ? "Stop" : "Start");

    // Update physical port settings controls
    ui->portComboBox->setEnabled(!isRunning);
    ui->refreshButton->setEnabled(!isRunning);
    ui->baudRateComboBox->setEnabled(!isRunning);
    ui->dataBitsComboBox->setEnabled(!isRunning);
    ui->parityComboBox->setEnabled(!isRunning);
    ui->stopBitsComboBox->setEnabled(!isRunning);
    ui->flowControlComboBox->setEnabled(!isRunning);
    ui->endpointListWidget->setEnabled(!isRunning);
    ui->addSerialButton->setEnabled(!isRunning);
    ui->removeButton->setEnabled(!isRunning);
    ui->addUdpButton->setEnabled(!isRunning);

    // Update data input controls
    ui->dataInputEdit->setEnabled(isRunning);
    ui->sendButton->setEnabled(isRunning);
    ui->targetComboBox->setEnabled(isRunning);
    ui->hexInputCheckBox->setEnabled(isRunning);

    // Update status bar
    m_statusLabel->setText(isRunning ? "Running" : "Ready");

    updateTargetComboBox();
}

void MainWindow::updateTargetComboBox()
{
    // Save current selection if possible
    QString currentText = ui->targetComboBox->currentText();

    // Clear and add default items
    ui->targetComboBox->clear();
    ui->targetComboBox->addItem("Physical Port");
    ui->targetComboBox->addItem("All Endpoints");

    // Add all endpoints
    for (auto item : m_dataControl->endPortsList()) {
        ui->targetComboBox->addItem(item.portName);
    }

    // Restore previous selection if it exists
    int index = ui->targetComboBox->findText(currentText);
    if (index >= 0) {
        ui->targetComboBox->setCurrentIndex(index);
    }
}

void MainWindow::refreshSerialPorts()
{
    QString currentPort = ui->portComboBox->currentText();

    m_curSerialList.clear();
    ui->portComboBox->clear();
    const auto serialPortInfos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &info : serialPortInfos) {
        m_curSerialList.append(QString::asprintf("%s-%s", info.portName().toUtf8().constData(), info.description().toUtf8().constData()));
    }
    ui->portComboBox->addItems(m_curSerialList);

    // Try to restore previously selected port
    int index = ui->portComboBox->findText(currentPort);
    if (index >= 0) {
        ui->portComboBox->setCurrentIndex(index);
    }
}

void MainWindow::addLogMessage(const QString &message)
{
    const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    QString logLine = QString("[%1] %2").arg(timestamp, message);
    ui->taskLogEdit->append(logLine);
    qDebug() << logLine;

    if (ui->autoScrollCheckBox->isChecked()) {
        ui->taskLogEdit->verticalScrollBar()->setValue(ui->taskLogEdit->verticalScrollBar()->maximum());
    }
}

void MainWindow::addDataLog(const QString &source, const QByteArray &data, const QString &direction, bool isImmediate)
{
    if (data.isEmpty()) {
        return;
    }

    const bool hexMode = ui->hexDisplayCheckBox->isChecked();
    const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    const QString fmtLabel = hexMode ? "HEX" : "ASCII";
    const QString headerKey = QString("%1 %2").arg(direction, fmtLabel);

    if (isImmediate) {
        ui->dataLogTextEdit->append(QString("[%1][%2]# %3> \n").arg(timestamp, source).arg(headerKey));
        if (hexMode) {
            const QString dataStr = DataFormatter::toDisplayString(data, true);
            ui->dataLogTextEdit->append(dataStr);
        } else {
            const QString text = QString::fromUtf8(data);
            // 直接插入文本，不人为添加分行，保证连续性
            ui->dataLogTextEdit->append(text);
        }
        return;
    }

    // 累积到输入缓冲区，达到阈值或遇到换行才输出
    QByteArray &buffer = m_asciiPendingBySource[source];
    buffer.append(data);

    int flushBytes = 0;
    if (hexMode) {
        if (buffer.size() < m_dataFlushThresholdBytes) {
            return;
        }
        flushBytes = (buffer.size() / m_dataFlushThresholdBytes) * m_dataFlushThresholdBytes;
    } else {
        const int lastNl = buffer.lastIndexOf('\n');
        if (lastNl >= 0) {
            flushBytes = lastNl + 1; // 按行边界输出
        } else if (buffer.size() >= m_dataFlushThresholdBytes) {
            flushBytes = (buffer.size() / m_dataFlushThresholdBytes) * m_dataFlushThresholdBytes;
        } else {
            return;
        }
    }

    // 打印头部（仅第一次出现该上下文 + 源）
    const QString headerKeyWithSource = headerKey + "|" + source;
    if (!m_printedHeaders.contains(headerKeyWithSource)) {
        ui->dataLogTextEdit->append(QString("[%1][%2]# %3> \n").arg(timestamp, source).arg(headerKey));
        m_printedHeaders.insert(headerKeyWithSource);
    }

    const QByteArray toFlush = buffer.left(flushBytes);
    buffer = buffer.mid(flushBytes);

    if (hexMode) {
        const QString dataStr = DataFormatter::toDisplayString(toFlush, true);
        ui->dataLogTextEdit->append(dataStr);
    } else {
        const QString text = QString::fromUtf8(toFlush);
        // 直接插入文本，不人为添加分行，保证连续性
        ui->dataLogTextEdit->append(text);
    }

    if (ui->autoScrollCheckBox->isChecked()) {
        ui->dataLogTextEdit->verticalScrollBar()->setValue(ui->dataLogTextEdit->verticalScrollBar()->maximum());
    }
}

void MainWindow::addSerialPortToEndPoints(const QString &portName, bool isVirtual)
{
    if (portName.isEmpty()) {
        return;
    }

    if (isVirtual) {
        const PortPair* pair = PortDeviceModel::getPairFromPortName(portName);
        if (PortDeviceModel::isEndPoint(pair->portA()->portName)
            || PortDeviceModel::isEndPoint(pair->portB()->portName)) {
            QMessageBox::warning(this, "Warning", "One Pair Only Have One Endpoint Port");
            return;
        }
    }

    addLogMessage("Added serial port endpoint: " + portName);

    // 更新模型中的端点选择状态，用于第三列状态灯显示
    if (m_driverController) {
        m_driverController->setEndpointSelected(portName, true);
    }

    // 去重
    if (ui->endpointListWidget->findItems(portName, Qt::MatchExactly).empty()) {
        ui->endpointListWidget->addItem(portName);
    }
}

/***************** Slots Handler *****************/

void MainWindow::onStartStopButtonClicked()
{
    if (!m_isRunning) {
        // Start
        QString portName = ui->portComboBox->currentText().split('-').first();
        if (portName.isEmpty()) {
            QMessageBox::warning(this, "Error", "Please select a physical serial port");
            return;
        }

        // Set serial port parameters
        BaudRate baudRate = static_cast<BaudRate>(ui->baudRateComboBox->currentText().toInt());

        DataBits dataBits;
        switch (ui->dataBitsComboBox->currentText().toInt()) {
        case 5: dataBits = QSerialPort::Data5; break;
        case 6: dataBits = QSerialPort::Data6; break;
        case 7: dataBits = QSerialPort::Data7; break;
        default: dataBits = QSerialPort::Data8; break;
        }

        Parity parity;
        switch (ui->parityComboBox->currentIndex()) {
        case 1: parity = QSerialPort::OddParity; break;
        case 2: parity = QSerialPort::EvenParity; break;
        default: parity = QSerialPort::NoParity; break;
        }

        StopBits stopBits;
        switch (ui->stopBitsComboBox->currentIndex()) {
        case 1: stopBits = QSerialPort::OneAndHalfStop; break;
        case 2: stopBits = QSerialPort::TwoStop; break;
        default: stopBits = QSerialPort::OneStop; break;
        }

        FlowControl flowControl;
        switch (ui->flowControlComboBox->currentIndex()) {
        case 1: flowControl = QSerialPort::HardwareControl; break;
        case 2: flowControl = QSerialPort::SoftwareControl; break;
        default: flowControl = QSerialPort::NoFlowControl; break;
        }

        // Set physical serial port
        PortConfig cfg(portName, baudRate);
        cfg.dataBits = dataBits;
        cfg.stopBits = stopBits;
        cfg.parity = parity;
        cfg.flowControl = flowControl;
        if (!m_dataControl->setInputPort(cfg)) {
            QMessageBox::warning(this, "Error", "Cannot set physical serial port");
            return;
        }
        // set to model
        if (m_driverController) {
            m_driverController->setInputSelected(portName);
        }

        // add virtual serial port
        for (int i = 0; i < ui->endpointListWidget->count(); ++i) {
            QString itemName = ui->endpointListWidget->item(i)->text();
            if (itemName.isEmpty() && itemName.startsWith("COM")) {
                continue;
            }
            cfg.portName = itemName;
            if (!m_dataControl->addEndPointPort(cfg)) {
                continue;
            }
        }

        // Start the forward
        if (!m_dataControl->startService()) {
            QMessageBox::warning(this, "Error", "Cannot start data control");
            return;
        }

        m_isRunning = true;
        addLogMessage("Serial port forward started");
    } else {
        // Stop
        m_dataControl->stopService();
        m_isRunning = false;
        addLogMessage("Serial port forward stopped");
    }

    updateUiState();
}

void MainWindow::onAddSerialEndpointClicked()
{
    QStringList availablePorts;
    for (const QString &info : m_curSerialList) {
        // 排除虚拟端口
        auto infoList = info.split("-");
        auto desc = infoList.at(1);
        auto name = infoList.at(0);
        if (!ui->endpointListWidget->findItems(name, Qt::MatchExactly).size()) {
            if (!desc.startsWith(C0C_SERVICE)) {
                availablePorts << info;
            }
        }
    }

    if (availablePorts.isEmpty()) {
        QMessageBox::warning(this, "Error", "No available serial ports");
        return;
    }

    bool ok;
    QString portInfo = QInputDialog::getItem(this, "Add Serial Endpoint", "Select serial port:", availablePorts, 0, false, &ok);
    if (!ok || portInfo.isEmpty()) {
        return;
    }

    addSerialPortToEndPoints(portInfo.split("-").first());
}

void MainWindow::onAddUdpEndpointClicked()
{
    bool ok;
    QString name = QInputDialog::getText(this, "Add UDP Endpoint", "Endpoint name:", QLineEdit::Normal, "UDP", &ok);
    if (!ok || name.isEmpty()) {
        return;
    }

    QString addressStr = QInputDialog::getText(this, "Add UDP Endpoint", "Target address:", QLineEdit::Normal, "127.0.0.1", &ok);
    if (!ok || addressStr.isEmpty()) {
        return;
    }

    QHostAddress address(addressStr);
    if (address.isNull()) {
        QMessageBox::warning(this, "Error", "Invalid IP address");
        return;
    }

    int port = QInputDialog::getInt(this, "Add UDP Endpoint", "Target port:", 8000, 1, 65535, 1, &ok);
    if (!ok) {
        return;
    }

    // TODO ADD
    addLogMessage("Added UDP endpoint: " + name + " -> " + addressStr + ":" + QString::number(port));
}

void MainWindow::onRemoveEndpointClicked()
{
    QList<QListWidgetItem *> items = ui->endpointListWidget->selectedItems();
    if (items.isEmpty()) {
        QMessageBox::warning(this, "Error", "Please select an endpoint to remove");
        return;
    }

    QStringList portNames;
    for (auto *port : items) {
        const QString name = port->text();
        portNames.append(name);
        // 更新模型中的端点选择状态（移除 -> 状态灯变为绿）
        if (m_driverController) {
            m_driverController->setEndpointSelected(name, false);
        }
        const int row = ui->endpointListWidget->row(port);
        QListWidgetItem *removed = ui->endpointListWidget->takeItem(row);
        ui->endpointListWidget->removeItemWidget(removed);
    }

    addLogMessage("Removed endpoint: " + portNames.join(","));
}

void MainWindow::onSendButtonClicked()
{
    const QString target = ui->targetComboBox->currentText();
    const QString input = ui->dataInputEdit->text();

    if (input.isEmpty()) {
        return;
    }

    bool ok = true;
    QString error;
    const bool hexMode = ui->hexInputCheckBox->isChecked();
    const QByteArray data = DataFormatter::parseInput(input, hexMode, &ok, &error);
    if (!ok) {
        QMessageBox::warning(this, "Error", error.isEmpty() ? "Invalid input" : error);
        return;
    }

    if (target == "Physical Port") {
        m_dataControl->sendToInputPort(data);
        addDataLog("INPUT", data, "<-");
    } else if (target == "All Endpoints") {
        m_dataControl->sendToAllEndpoints(data);
        addDataLog("All Endpoints", data, "<-", true);
    } else {
        m_dataControl->sendToEndpointPort(target, data);
        addDataLog(target, data, "<-", true);
    }

    ui->dataInputEdit->clear();
}

void MainWindow::onInputPortDataReceived(const QByteArray &data)
{
    // 改为非即时：缓冲到阈值或遇到换行再输出，避免碎片
    addDataLog("INPUT", data, "->", false);
}

void MainWindow::onEndpointPortDataReceived(const QString &name, const QByteArray &data)
{
    addDataLog(name, data, "->", true);
}

void MainWindow::onError(const QString &message)
{
    QMessageBox::critical(this, "Error", message);
    addLogMessage("Error: " + message);
}

void MainWindow::onDataFlushTimerTick()
{
    // 按源冲刷：尽量以换行边界输出，避免碎片
    if (m_asciiPendingBySource.isEmpty()) {
        return;
    }

    const bool hexMode = ui->hexDisplayCheckBox->isChecked();
    const QString fmtLabel = hexMode ? "HEX" : "ASCII";
    const QString headerKey = QString("%1 %2").arg("->", fmtLabel);
    const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");

    for (auto it = m_asciiPendingBySource.begin(); it != m_asciiPendingBySource.end(); ++it) {
        const QString source = it.key();
        QByteArray &pending = it.value();
        if (pending.isEmpty()) {
            continue;
        }

        // 打印头部（仅第一次出现该上下文 + 源）
        const QString headerKeyWithSource = headerKey + "|" + source;
        if (!m_printedHeaders.contains(headerKeyWithSource)) {
            ui->dataLogTextEdit->append(QString("[%1][%2]# %3> \n").arg(timestamp, source).arg(headerKey));
            m_printedHeaders.insert(headerKeyWithSource);
        }

        if (hexMode) {
            const QString dataStr = DataFormatter::toDisplayString(pending, true);
            ui->dataLogTextEdit->append(dataStr);
            pending.clear();
        } else {
            const int lastNl = pending.lastIndexOf('\n');
            if (lastNl < 0) {
                continue; // 没有完整行，等待下一次
            }
            const QByteArray toFlush = pending.left(lastNl + 1);
            const QString text = QString::fromUtf8(toFlush);
            ui->dataLogTextEdit->append(text);
            pending = pending.mid(lastNl + 1);
        }
    }

    if (ui->autoScrollCheckBox->isChecked()) {
        ui->dataLogTextEdit->verticalScrollBar()->setValue(ui->dataLogTextEdit->verticalScrollBar()->maximum());
    }
}

void MainWindow::onStatsUpdated(const TransferStats &total, const EndpointStatsMap &perEndpoint)
{
    Q_UNUSED(perEndpoint);
    if (!m_statsLabel) return;

    auto fmt = [](double bps) -> QString {
        const double kb = 1024.0;
        const double mb = kb * 1024.0;
        if (bps >= mb) return QString("%1 MB/s").arg(bps / mb, 0, 'f', 2);
        if (bps >= kb) return QString("%1 KB/s").arg(bps / kb, 0, 'f', 1);
        return QString("%1 B/s").arg(bps, 0, 'f', 0);
    };

    const QString text = QString("Rx %1 | Tx %2 | Out %3 | EP %4 | Err %5")
        .arg(fmt(total.inputRxBps))
        .arg(fmt(total.inputTxBps))
        .arg(fmt(total.outputsTxBps))
        .arg(fmt(total.endpointsRxBps))
        .arg(QString::number(total.totalErrors));
    m_statsLabel->setText(text);
}
